#include <unordered_set>
#include <unordered_map>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

// 127. 单词接龙
class Solution 
{
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) 
    {
        unordered_set<string> dict(wordList.begin(), wordList.end());
        if(!dict.count(endWord)) return 0;

        unordered_set<string> smallLevel, bigLevel, nextLevel;
        smallLevel.insert(beginWord);
        bigLevel.insert(endWord);
        for(int len = 2; !smallLevel.empty(); ++len)
        {
            for(auto& str : smallLevel)
            {
                string tmp = str;
                for(int i = 0; i < str.size(); ++i)
                {
                    char old = tmp[i];
                    for(char ch = 'a'; ch <= 'z'; ++ch)
                    {
                        if(ch != old)
                        {
                            tmp[i] = ch;
                            // 找到最短转换序列
                            if(bigLevel.count(tmp))
                            {
                                return len;
                            }
                            // 字典中存在该单词，从字典中删除防止往回遍历
                            if(dict.count(tmp))
                            {
                                dict.erase(tmp);
                                nextLevel.insert(tmp);
                            }
                        }
                    }
                    tmp[i] = old;
                }
            }
            if(nextLevel.size() <= bigLevel.size())
            {
                smallLevel.swap(nextLevel);
            }
            else
            {
                bigLevel.swap(nextLevel);
                smallLevel.swap(nextLevel);
            }
            nextLevel.clear();
        }
        return 0;
    }
};

// 洛谷：世界冰球锦标赛 / 牛客：零食问题
const int MAXN = 40;
const int MAXM = 1 << 20;
vector<long> arr(MAXN);
vector<long> lsum(MAXM);
vector<long> rsum(MAXM);
// w: 背包容量限制
long n, w;

// arr[i...e]结束，e再往右就不展开了
// s是累加和
// 返回值：ans数组填到了什么位置
int f(int i, int e, long s, vector<long>& ans, int j)
{
    if(s > w) return j;
    if(i == e)
    {
        ans[j++] = s;
    }
    else
    {
        // 不要arr[i];
        j = f(i + 1, e, s, ans, j);
        // 要arr[i]
        j = f(i + 1, e, s + arr[i], ans, j);
    }
    return j;
}

long compute()
{
    int lsize = f(0, n >> 1, 0, lsum, 0);
    int rsize = f(n >> 1, n, 0, rsum, 0);
    sort(lsum.begin(), lsum.begin() + lsize);
    sort(rsum.begin(), rsum.begin() + rsize);
    
    long ans = 0;
    // 双指针
    for(int i = lsize - 1, j = 0; i >= 0; --i)
    {
        while(j < rsize && lsum[i] + rsum[j] <= w) ++j;
        ans += j;
    }
    return ans;
}

int main()
{
    cin >> n >> w;
    for(int i = 0; i < n; ++i) cin >> arr[i];
    cout << compute() << endl;
    
    return 0;
}

// 1755. 最接近目标值的子序列和
class Solution 
{
    const int MAXN = 1 << 20;
    vector<int> lsum;
    vector<int> rsum;
    int fill; // 填充到哪

    // e：结束边界, i：当前遍历到的位置，s：累加和，fill：填充数组的下摆哦
    void collect(vector<int>& nums, int i, int e, int s, vector<int>& sum)
    {
        if(i == e) sum[fill++] = s;
        else
        {
            // nums[i...] 这一组相同的数字有几个
            int j = i + 1;
            // nums[ 1 1 1 1 1 2 ....]
            //       i         j   
            while(j < e && nums[j] == nums[i]) ++j;
            for(int k = 0; k <= j - i; ++k)
            {
                collect(nums, j, e, s + k * nums[i], sum);
            }
        }
    }

public:
    int minAbsDifference(vector<int>& nums, int goal) 
    {
        int n = nums.size();
        lsum.resize(MAXN), rsum.resize(MAXN);
        int mn = 0, mx = 0;
        for(int i = 0; i < n; ++i)
        {
            if(nums[i] >= 0) mx += nums[i];
            else mn += nums[i];
        }

        if(mx < goal) return abs(mx - goal);
        if(mn > goal) return abs(mn - goal);

        sort(nums.begin(), nums.end());
        fill = 0;
        collect(nums, 0, n >> 1, 0, lsum);
        int lsize = fill;
        fill = 0;
        collect(nums, n >> 1, n, 0, rsum);
        int rsize = fill;
        sort(lsum.begin(), lsum.begin() + lsize);
        sort(rsum.begin(), rsum.begin() + rsize);

        int ans = abs(goal);
        for(int i = 0, j = rsize - 1; i < lsize; ++i)
        {
            while(j > 0 && abs(goal - lsum[i] - rsum[j - 1]) <= abs(goal - lsum[i] - rsum[j])) --j;
            ans = min(ans, abs(goal - lsum[i] - rsum[j]));
        }
        return ans;
    }
};

// 141. 环形链表
class Solution 
{
public:
    bool hasCycle(ListNode *head) 
    {
        ListNode *slow = head, *fast = head;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast) return true;
        }    
        return false;
    }
};

// 21. 合并两个有序链表
class Solution 
{
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        if(!l1) return l2;
        if(!l2) return l1;

        if(l1->val <= l2->val)
        {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else
        {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

// 2. 两数相加
class Solution 
{
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2, int carry = 0) 
    {
        if(!l1 && !l2) return carry ? new ListNode(carry) : nullptr;

        if(l1 == nullptr) swap(l1, l2);
        carry += l1->val + (l2 ? l2->val : 0);
        l1->val = carry % 10;
        l1->next = addTwoNumbers(l1->next, (l2 ? l2->next : nullptr), carry / 10);
        return l1;
    }
};